#include <QtGui/QPushButton>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QAction>
#include <QtGui/QLabel>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include "treewidget.h"
#include "const.h"
#include "usbwizard.h"
#include "udevrule.h"
#include "usbmanager.h"

//===================================================//
//================= File Parser =====================//
//===================================================//

UdevFileParser::UdevFileParser(const QString& path) {
	filePath = path.isEmpty() ? "/etc/udev/rules.d/01-mountmanager.rules" : path;
	parseFile();
}

UdevFileParser::~UdevFileParser() {
	foreach (UdevRule *rule,rules)
		delete rule;
}

const QList<UdevRule *>& UdevFileParser::getRules() const {
	return rules;
}

void UdevFileParser::parseFile() {
	rules.clear();
	QFile file(filePath);
	if (file.open(QIODevice::ReadOnly)) {
		QTextStream stream(&file);
		QString content = stream.readAll();
		QStringList rulesStrings = content.split("#DontRemoveThisRow#");
		foreach (QString ruleString,rulesStrings) {
			if (ruleString.trimmed().isEmpty())
				continue;
			UdevRule *newRule = new UdevRule;
			QString fileSystem;
			
			QStringList ruleLines = ruleString.split("\n");
			foreach (QString str,ruleLines) {
				QStringList optionsList = str.split(",");
				foreach (QString option,optionsList) {
					if (option.contains("KERNEL") && newRule->getName().isEmpty())
						newRule->setName(option.replace("KERNEL==","").replace("\"","").replace(" ",""));
					else if (option.contains("SYSFS{vendor}") && newRule->getVendor().isEmpty())
						newRule->setVendor(option.replace("SYSFS{vendor}==","").replace("\"","").replace(" ",""));
					else if (option.contains("SYSFS{model}") && newRule->getModel().isEmpty())
						newRule->setModel(option.replace("SYSFS{model}==","").replace("\"","").replace(" ",""));
					else if (option.contains("BUS") && newRule->getBus().isEmpty())
						newRule->setBus(option.replace("BUS==","").replace("\"","").replace(" ",""));
					else if (option.contains("SUBSYSTEM") && newRule->getSubsystem().isEmpty())
						newRule->setSubsystem(option.replace("SUBSYSTEM==","").replace("\"","").replace(" ",""));
					else if (option.contains("GROUP"))
						newRule->setGroup(option.replace("GROUP=","").replace("\"","").replace(" ",""));
					else if (option.contains("OWNER"))
						newRule->setOwner(option.replace("OWNER=","").replace("\"","").replace(" ",""));
					
					if (option.contains("RESULT")) 
						fileSystem= option.replace("RESULT==","").replace("\"","").replace(" ","");
					else if (option.contains("RUN")) {
						QStringList list = option.replace("RUN+=","").replace("\"","").split(" ");
						list.removeAll("");
						list.removeAll(" ");
						if (list.count() == 7) {
							newRule->setMountPoint(list[6]);
							newRule->addOptionsWithFileSystem(fileSystem,list[4]);
						}
					}
				}
			}
			rules << newRule;
		}
	}
}

void UdevFileParser::saveRules(QList<UdevRule *> rulesToSave) {
	QFile file(filePath);
	if (file.open(QIODevice::WriteOnly)) {
		QTextStream stream(&file);
		foreach(UdevRule *rule,rulesToSave)
			if (!rule->isNull())
				stream << rule->getFileStringOfTheRule() << "#DontRemoveThisRow#\n";
	}
}

//===================================================//
//================= USB Manager =====================//
//===================================================//

UsbManager::UsbManager(PopupWindow *popupWindow,QWidget *parent) : QDialog(parent) {

	usbWizard = new UsbWizard(popupWindow,parent);
	connect(usbWizard,SIGNAL(ruleEdited(UdevRule *)),this,SLOT(editRule(UdevRule *)));
	connect(usbWizard,SIGNAL(ruleCreated(UdevRule *)),this,SLOT(createRule(UdevRule *)));
	
	parser = new UdevFileParser;
	viewer = new UdevRuleViewer;
	
	rulesView = new TreeWidget(true);
	rulesView->setColumnCount(4);
	rulesView->setHeaderLabels(QStringList() << tr("Device") << tr("Vendor") << tr("Model") << tr("Bus"));
	rulesView->setContextMenuIcon(QIcon(ICONS_PATH"usb_disk.png"));
	rulesView->setContextMenuHeader(tr("USB Manager"));
	connect(rulesView,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this,SLOT(viewFullRule(QTreeWidgetItem*,int)));
	
	createRuleButton = new QPushButton(tr("Create"));
	connect(createRuleButton,SIGNAL(clicked()),usbWizard,SLOT(exec()));
	
	editRuleButton = new QPushButton(tr("Edit"));
	connect(editRuleButton,SIGNAL(clicked()),this,SLOT(editRuleByWizard()));
	
	removeRuleButton = new QPushButton(tr("Remove"));
	connect(removeRuleButton,SIGNAL(clicked()),this,SLOT(removeRule()));
	
	createRuleAction = new QAction(rulesView);
	createRuleAction->setText(tr("Create"));
	connect(createRuleAction,SIGNAL(triggered()),usbWizard,SLOT(exec()));
	
	editRuleAction = new QAction(rulesView);
	editRuleAction->setText(tr("Edit"));
	connect(editRuleAction,SIGNAL(triggered()),this,SLOT(editRuleByWizard()));
	
	removeRuleAction = new QAction(rulesView);
	removeRuleAction->setText(tr("Remove"));
	connect(removeRuleAction,SIGNAL(triggered()),this,SLOT(removeRule()));
	
	viewFullRuleAction = new QAction(rulesView);
	viewFullRuleAction->setText(tr("View full rule"));
	connect(viewFullRuleAction,SIGNAL(triggered()),this,SLOT(viewFullRule()));
	
	rulesView->addContextMenuAction(createRuleAction);
	rulesView->addContextMenuAction(editRuleAction);
	rulesView->addContextMenuAction(removeRuleAction);
	rulesView->addContextMenuSeparator();
	rulesView->addContextMenuAction(viewFullRuleAction);
	
	QHBoxLayout *buttonsLayout = new QHBoxLayout;
	buttonsLayout->addStretch();
	buttonsLayout->addWidget(createRuleButton);
	buttonsLayout->addWidget(editRuleButton);
	buttonsLayout->addWidget(removeRuleButton);
	buttonsLayout->addStretch();
	
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addWidget(rulesView,1);
	mainLayout->addWidget(viewer);
	mainLayout->addLayout(buttonsLayout);
	setLayout(mainLayout);
	setWindowTitle(tr("USB Manager"));
	resize(600,400);
	
	updateRulesView();
}

UsbManager::~UsbManager() {
	delete usbWizard;
	
	delete createRuleAction;
	delete editRuleAction;
	delete removeRuleAction;
	delete viewFullRuleAction;
	
	delete rulesView;
	
	delete createRuleButton;
	delete editRuleButton;
	delete removeRuleButton;
}

UsbWizard *UsbManager::getWizard() const {
	return usbWizard;
}

void UsbManager::updateRulesView() {
	rules.clear();
	foreach (UdevRule *rule,parser->getRules()) {
		QTreeWidgetItem *newItem = new QTreeWidgetItem(rulesView);
		setRuleToItem(newItem,rule);
		rules.insert(newItem,rule);
	}
}

void UsbManager::viewFullRule(QTreeWidgetItem *item,int) {
	if (item == 0)
		item = rulesView->currentItem();
	if (item == 0)
		return;
	viewer->setRule(rules[item]);
	viewer->show();
}

void UsbManager::editRuleByWizard() {
	QTreeWidgetItem *item = rulesView->currentItem();
	if (item == 0)
		return;
	usbWizard->editUdevRule(rules[item]);
	usbWizard->exec();
}

void UsbManager::editRule(UdevRule *rule) {
	updateRuleView(rule);
	parser->saveRules(rules.values());
}

void UsbManager::updateRuleView(UdevRule *rule) {
	if (!rules.keys(rule).isEmpty()) {
		QTreeWidgetItem *item = rules.key(rule);
		if (item == 0)
			return;
		setRuleToItem(item,rule);
		viewer->setRule(rule);
	}
}

void UsbManager::createRule(UdevRule *newRule) {
	QTreeWidgetItem *newItem = new QTreeWidgetItem(rulesView);
	setRuleToItem(newItem,newRule);
	rules.insert(newItem,newRule);
	parser->saveRules(rules.values());
}

void UsbManager::setRuleToItem(QTreeWidgetItem *item,UdevRule *rule) {
	item->setText(0,rule->getName().isEmpty() ? tr("Unknown") : rule->getName());
	item->setText(1,rule->getVendor().isEmpty() ? tr("Unknown") : rule->getVendor());
	item->setText(2,rule->getModel().isEmpty() ? tr("Unknown") : rule->getModel());
	item->setText(3,rule->getBus().isEmpty() ? tr("Unknown") : rule->getBus());
}

void UsbManager::removeRule() {
	QTreeWidgetItem *item = rulesView->currentItem();
	if (item == 0)
		return;
	UdevRule *rule = rules[item];
	rules.remove(item);
	delete rule;
	delete item;
	viewer->hide();
	parser->saveRules(rules.values());
}

//===================================================//
//================ Udev Rule View ===================//
//===================================================//

UdevRuleViewer::UdevRuleViewer() {
	
	label = new QLabel;
	label->setWordWrap(true);
	
	closeButton = new QPushButton;
	closeButton->setFlat(true);
	closeButton->setIcon(QIcon(ICONS_PATH"cancel.png"));
	connect(closeButton,SIGNAL(clicked()),this,SLOT(hide()));
	
	QHBoxLayout *topLayout = new QHBoxLayout;
	topLayout->addStretch();
	topLayout->addWidget(closeButton);
	
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->addLayout(topLayout);
	mainLayout->addWidget(label,1);
	setLayout(mainLayout);
	
	hide();
}

UdevRuleViewer::~UdevRuleViewer() {
	delete label;
	delete closeButton;
}

void UdevRuleViewer::setRule(UdevRule *rule) {
	QString labelText;
	
	labelText += "<b>" + tr("Subsystem") + "</b>: " + rule->getSubsystem() + "<br>";
	labelText += "<b>" + tr("Mount point") + "</b>: " + rule->getMountPoint() + "<br>";
	labelText += "<b>" + tr("Group") + "</b>: " + rule->getGroup() + "<br>";
	labelText += "<b>" + tr("Owner") + "</b>: " + rule->getOwner() + "<br>";
	labelText += tr("Remove mount point after device disconnection") + ": <b>";
	labelText += rule->getRemoveMountPoint() ? tr("yes") : tr("no");
	labelText += "</b><br>";
	
	labelText += "<b>" + tr("Options for file systems") + "</b>:";
	labelText += "<table border=0>";
	QMap<QString,QString> optionsWithFileSystems = rule->getOptionsWithFileSystems();
	for (QMap<QString,QString>::const_iterator i = optionsWithFileSystems.constBegin(); 
								i != optionsWithFileSystems.constEnd(); ++i)
		labelText += "<tr><td><b>" + i.key() + "</b> - </td><td>" + i.value() + "</tr>";
	labelText += "</table>";
	
	label->setText(labelText);
}
